package mail_remote_control;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.Properties;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.RecipientId;
import org.bouncycastle.cms.RecipientInformation;
import org.bouncycastle.cms.RecipientInformationStore;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.mail.smime.SMIMEEnveloped;
import org.bouncycastle.mail.smime.SMIMEException;
import org.bouncycastle.mail.smime.SMIMEUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.mail.smime.SMIMEEnvelopedGenerator;
import org.bouncycastle.mail.smime.SMIMESigned;
import org.bouncycastle.mail.smime.SMIMESignedGenerator;

/**
 *
 * @author Krzysztof Lech (Stiopa)
 */
public class Mail {
    
    public int countmail = 0;
    public String command = "";
    public String tekst = "";
    public String from = "";
    private String passwd = "";
    private String storepath;
    private String alias;
    private String pop3,smtp,user,password;

    Mail(String p3, String s,String u,String p, String storepath, String passwd, String alias) throws NoSuchProviderException,
            MessagingException, IOException {
        pop3 = p3;
        smtp = s;
        user = u;
        password = p;
        this.passwd = passwd;
        this.storepath = storepath;
        this.alias = alias;
    }

    void getMail() throws FileNotFoundException, KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, NoSuchProviderException, MessagingException, CMSException, java.security.NoSuchProviderException, SMIMEException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, Exception{
        Security.addProvider(new BouncyCastleProvider());
        KeyStore ks = getKeyStore(storepath, passwd);
        PrivateKey privKey = (PrivateKey) ks.getKey( alias, passwd.toCharArray());
        Properties props =new Properties();
        Session session = Session.getInstance(props, null);
        Store store = session.getStore("pop3");
        store.connect(pop3,user,password);
        Folder folder = store.getFolder("INBOX");
        folder.open(Folder.READ_ONLY);
        Message message[] = folder.getMessages();
        System.out.println(folder.getMessageCount());
        for (int i = countmail;  i < folder.getMessageCount(); i++){
            System.out.println(message[i].getSubject());
            if(message[i].isMimeType("application/pkcs7-mime")){
                MimeMessage msg = (MimeMessage)message[i];
                SMIMEEnveloped m = new SMIMEEnveloped(msg);
                RecipientId     recId = new RecipientId();
                Certificate[] chain = ks.getCertificateChain(alias);
                X509Certificate cert = (X509Certificate)chain[0];
                recId.setSerialNumber(cert.getSerialNumber());
                recId.setIssuer(cert.getIssuerX500Principal().getEncoded());
                RecipientInformationStore   recipients = m.getRecipientInfos();
                RecipientInformation        recipient = recipients.get(recId);
                MimeBodyPart res = SMIMEUtil.toMimeBodyPart(recipient.getContent(privKey,"BC"));
                if (res.getContent() instanceof MimeMultipart ){
                    if (res.isMimeType("multipart/signed")){
                        SMIMESigned signed = new SMIMESigned((MimeMultipart)res.getContent());
                         X509Certificate rootCert = (X509Certificate)ks.getCertificate(alias);
                         if (isValid(signed, rootCert, ks.getCertificate(alias).getPublicKey())){
                            System.out.println("Podpis jest OK!");
                            MimeBodyPart content = signed.getContent();
                            if (content.getContent() instanceof MimeMultipart ){
                                MimeMultipart mpart = (MimeMultipart)content.getContent();
                                for (int p=0, n=mpart.getCount(); p < n; p++)
                                {
                                    Part part = mpart.getBodyPart(p);
                                    String disposition = part.getDisposition();
                                    Object o = part.getContent();
                                    if ((disposition != null) && ((disposition.equals(Part.ATTACHMENT)) ||
                                        (disposition.equals(Part.INLINE)))) {
                                        Terminal term = new Terminal(command);
                                        if (!command.isEmpty()){
                                            term.commandParse();
                                            System.out.println(term.script+"/"+part.getFileName());
                                            saveFile(term.script+"/"+part.getFileName(), part);
                                        }
                                    }else if (o instanceof String){
                                        command = (String)o;
                                    }
                                }
                            }else{
                                command = (String)content.getContent();
                            }
                         }
                    }
                }
            }
        }
        countmail = folder.getMessageCount();
    }
    
    void sendMail(String destAddress, String from) throws AddressException, MessagingException, NoSuchAlgorithmException, java.security.NoSuchProviderException, SMIMEException, KeyStoreException, UnrecoverableKeyException, FileNotFoundException, IOException, CertificateException, InvalidKeyException{
        Security.addProvider(new BouncyCastleProvider());
        KeyStore ks = getKeyStore(storepath, passwd);
        PrivateKey privKey = (PrivateKey) ks.getKey( alias, passwd.toCharArray());
        X509Certificate rootCert = (X509Certificate)ks.getCertificate(alias);
        Properties props =new Properties();
        Session session = Session.getInstance(props, null);
        MimeBodyPart mmBodyPart = new MimeBodyPart();
        mmBodyPart.setText(tekst);
        SMIMESignedGenerator gen = new SMIMESignedGenerator();
        gen.addSigner(privKey, rootCert, SMIMESignedGenerator.DIGEST_SHA1);
        MimeMultipart mmultipart = gen.generate(mmBodyPart, "BC");
        MimeBodyPart signedPart = new MimeBodyPart();
        signedPart.setContent(mmultipart);
        SMIMEEnvelopedGenerator genEnveloped = new SMIMEEnvelopedGenerator();
        genEnveloped.addKeyTransRecipient(rootCert);
        MimeBodyPart envPart = genEnveloped.generate(signedPart, SMIMEEnvelopedGenerator.AES256_CBC, "BC");
        MimeMessage mail = new MimeMessage(session);
        mail.setFrom(new InternetAddress(from));
        mail.addRecipient(Message.RecipientType.TO,new InternetAddress(destAddress));
        mail.setSubject("testuje");
        MimeMultipart mmPart = new MimeMultipart();
        mmPart.addBodyPart(envPart);
        Transport transport = session.getTransport("smtp");
        transport.connect(smtp, user, password);
        mail.setContent(mmPart);
        transport.sendMessage(mail, mail.getAllRecipients());
        transport.close();
    }

    private void saveFile(String filename, Part part) throws FileNotFoundException,
            IOException, MessagingException{
         FileOutputStream fos = new FileOutputStream(filename);
         BufferedWriter out = new BufferedWriter(new OutputStreamWriter(fos, "UTF-8"));
         InputStream is = part.getInputStream();
         BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"));
         String line;
         while( (line = in.readLine()) != null ){
            out.write(line);
            out.newLine();
         }
         out.close();
         is.close();
         fos.close();
    }

    static boolean[] getKeyForSignature(){
        boolean[] val = new boolean[9];
        val[0] = true;
        return val;
    }
    private boolean isValid(SMIMESigned signed, X509Certificate rootCert, PublicKey pubKey) throws NoSuchAlgorithmException, java.security.NoSuchProviderException, CMSException {
       CertStore certAndCRLs = signed.getCertificatesAndCRLs("Collection", "BC");
       SignerInformationStore signers = signed.getSignerInfos();
       Iterator it = signers.getSigners().iterator();
       if (it.hasNext()){
           SignerInformation signer = (SignerInformation)it.next();
           X509CertSelector signerConstraints = signer.getSID();
           signerConstraints.setKeyUsage(getKeyForSignature());
           return signer.verify(pubKey, "BC");
       }
       return false;
    }

    static KeyStore getKeyStore(String storepath, String password) throws FileNotFoundException, KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException{
        InputStream fis = new FileInputStream(storepath);
        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(fis, password.toCharArray());
        return ks;
    }
}
